import React from 'react';
import ReactDOM from 'react-dom';
import { toJS } from "mobx";
import { observer } from "mobx-react";
import { createHashHistory } from 'History';
import { Router, Route, useRouterHistory } from 'react-router';
import classnames from 'classnames';
import {
  Table,
  Pagination,
  Button,
  Tooltip,
  Card,
  message,
  Collapse,
  Popconfirm,
  Menu,
  Dropdown,
  DatePicker,
  Tag,
  Popover,
  Row,
  Col,
  Switch
} from 'antd';
import {
  WeaTools,
  WeaInput,
  WeaTop,
  WeaBrowser,
  WeaScope,
  WeaDialog,
  WeaHelpfulTip,
  WeaEchart,
} from 'ecCom';
import { WeaTableNew } from 'comsMobx';

import M from './pages/M';
import PC from './pages/PC';

import './index.less';
import mock from './data';

const history = useRouterHistory(createHashHistory)({
  queryKey: '_key',
  basename: '/',
});

const { WeaTable, TableStore } = WeaTableNew;
const { callApi } = WeaTools;
const Panel = Collapse.Panel;
const RangePicker = DatePicker.RangePicker;

const tableStore = new TableStore();
const pcTableStore = new TableStore();

const detailContants = {
  PR_NAME: '名称',
  PR_START: '起点时间',
  PR_REDIRECT: '重定向耗时',
  PR_UNLOADEVENT: '前一个同域页面卸载耗时',
  PR_UNLOADEVENTSTART: '前一个页面卸载开始节点',
  PR_UNLOADEVENTEND: '前一个页面卸载结束节点',
  PR_APPCACHE: 'DNS 缓存检查耗时',
  PR_DOMAINLOOKUP: 'DNS 查询耗时',
  PR_DOMAINLOOKUPSTART: 'DNS 查询开始时间节点',
  PR_DOMAINLOOKUPEND: 'DNS 查询结束时间节点',
  PR_CONNECT: 'TCP 连接耗时',
  PR_CONNECTSTART: 'TCP 连接开始时间节点',
  PR_CONNECTEND: 'TCP 连接结束时间节点',
  PR_TTFB: '请求（TTFB）耗时',
  PR_REQUESTSTART: '请求 开始时间节点',
  PR_RESPONSESTART: '接收响应 开始时间节点',
  PR_RESPONSEEND: '接收响应 结束时间节点',
  PR_DOWNLOAD: '下载耗时',
  PR_NETWORK: '网络耗时',
  PR_DECODE: '解码耗时',
  PR_INTERACTIVE: '解析耗时',
  PR_DOMCONTENTLOADEDEVENT: 'DOMCONTENTLOADED 事件耗时',
  PR_DOMCONTENTLOADEDEVENTSTART: 'DOMCONTENTLOADED 事件触发时间节点',
  PR_DOMCONTENTLOADEDEVENTEND: 'DOMCONTENTLOADED 事件结束时间节点',
  PR_COMPLETE: '完全解析耗时',
  PR_LOADEVENT: 'ONLOAD 事件耗时',
  PR_LOADEVENTSTART: 'ONLOAD 事件起始节点',
  PR_LOADEVENTEND: 'ONLOAD 事件结束节点',
  PR_TOTAL: 'HTML 加载总耗时',
  PR_FIRSTPAINT: '首次绘制总耗时',
  PR_FIRSTCONTENTFULPAINT: '二次绘制总耗时',
  PR_ROOTDOMNODEINSERTED: 'RENDER 时间',
  PR_RENDER: 'RENDER 总耗时',
  PR_DEVICE: '设备类型',
  PR_BROWSER: '浏览器',
  PR_VERSION: '浏览器版本',
  PR_ENGINE: '浏览器引擎',
  PR_OS: '操作系统',
  PR_OSVERSION: '操作系统版本',
  PR_PERFORMANCEID: '记录号',
  PR_TYPE: '记录类型',
  PR_DES: '描述',
  PR_USERAGENT: 'UA 信息'
};

const orderContants = [
  "PR_NAME",
  "PR_START",
  "PR_REDIRECT",
  {
    name:'PR_UNLOADEVENT',
    detail: ['PR_UNLOADEVENTSTART', 'PR_UNLOADEVENTEND']
  },
  "PR_APPCACHE",
  {
    name:'PR_DOMAINLOOKUP',
    detail: ['PR_DOMAINLOOKUPSTART', 'PR_DOMAINLOOKUPEND']
  },
  {
    name:'PR_CONNECT',
    detail: ['PR_CONNECTSTART', 'PR_CONNECTEND']
  },
  {
    name:'PR_TTFB',
    detail: ['PR_REQUESTSTART', 'PR_RESPONSESTART', 'PR_RESPONSEEND']
  },
  "PR_DOWNLOAD",
  "PR_NETWORK",
  "PR_DECODE",
  "PR_INTERACTIVE",
  {
    name:'PR_DOMCONTENTLOADEDEVENT',
    detail: ['PR_DOMCONTENTLOADEDEVENTSTART', 'PR_DOMCONTENTLOADEDEVENTEND']
  },
  "PR_COMPLETE",
  {
    name:'PR_LOADEVENT',
    detail: ['PR_LOADEVENTSTART', 'PR_LOADEVENTEND']
  },
  "PR_TOTAL",
  "PR_FIRSTPAINT",
  "PR_FIRSTCONTENTFULPAINT",
  "PR_ROOTDOMNODEINSERTED",
  "PR_RENDER",
  "PR_DEVICE",
  "PR_BROWSER",
  "PR_VERSION" ,
  "PR_ENGINE",
  "PR_OS",
  "PR_OSVERSION",
  "PR_PERFORMANCEID",
  "PR_USERAGENT"
];

const widthContants = {
  PR_CHILDREN: 70,
  PR_USERNAME: 80,
  PR_NAME: 300,
  PR_DES: 100,
  PR_START: 120,
  PR_RENDER: 130,
  PR_NETWORK: 100,
  PR_BROWSER: 90,
  PR_OS: 90,
  PR_TTFB: 110,
  PR_DOWNLOAD: 100,
  PR_SUBCOMPANYNAME : 90,
  PR_DEPARTMENTNAME: 90,
};

const titleContants = {
  PR_CHILDREN: '详情',
  PR_USERNAME: '用户',
  PR_NAME: 'URL',
  PR_DES: '描述',
  PR_START: '记录时间',
  PR_RENDER: '总耗时 / ms',
  PR_NETWORK: '网络 / ms',
  PR_BROWSER: '浏览器',
  PR_OS: '操作系统',
  PR_TTFB: 'TTFB / ms',
  PR_DOWNLOAD: '下载 / ms',
  PR_SUBCOMPANYNAME : '分部',
  PR_DEPARTMENTNAME: '部门',
};

const helpContants = {
  PR_CHILDREN: '包含可能阻塞页面加载的主要资源和接口的详细信息（IE9不支持）',
  PR_RENDER: '从请求页面到看到主要内容渲染所花费的时间',
  PR_NETWORK: '请求 HTML文件的网络耗时，包括 TTFB 和下载的耗时',
  PR_TTFB: '浏览器向服务器发起请求到接收到服务器响应的时间',
  PR_DOWNLOAD: '接收到服务器响应到资源下载完毕的时间',
};

const filterContants = {
  PR_USERNAME: 'lastname',
  PR_NAME: 'name',
  PR_START: 'start',
  PR_RENDER: 'render',
  PR_DES: 'des',
  PR_BROWSER: 'browser',
  PR_SUBCOMPANYNAME : 'subcompanyname',
  PR_DEPARTMENTNAME: 'departmentname',
};

const initParams = {
  device: 'PC',
  startFrom: '',
  startTo: '',
  lastname: '',
  subcompanyname: '',
  departmentname: '',
  name: '',
  renderFrom: '',
  renderTo: '',
  des: '',
  browser: '',
  version: '',
};

const transformDate = (time) => `${new Date(time).toLocaleString().replace(/\s.*$/, '').replace(/\//g, '-')} ${new Date(time).toTimeString().replace(/\s.*$/, '')}`;

@observer
class Main extends React.Component {
  state = {
    y: 0,
    searchLoading: false,
    reportLoading: false,
    clearLoading: false,
    params: { ...initParams },
    lastnameData: [],
    subcompanynameData: [],
    departmentnameData: [],
    anlayzeData: [],
    showReport: false,
    sortParams: [],
    openLoading: false,
    isopen: false,
    visible: false,
    detailObj: {
      record: {},
      data: []
    }
  }

  componentDidMount() {
    this.search();
    this.caulate();
    this.getOpen();
    window.addEventListener('resize', this.componentDidUpdate.bind(this));
  }

  componentDidUpdate() {
    this.caulate();
    if (this.echart && this.state.anlayzeData.length) {
      this.echart.paint();
      if (this.echart.chart) {
        this.echart.chart.resize()
      }
    }
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.componentDidUpdate.bind(this));
  }

  caulate = () => {
    if (this.table && window.$) {
      const table = window.$(this.table);
      if (table) {
        const top = window.$(this.table).offset().top;
        const h = document.documentElement.clientHeight;
        const y = h - top - 90;
        if (y !== this.state.y) {
          this.setState({ y });
        }
      }
    }
  }

  clear = () => {
    this.setState({ clearLoading: true });
    callApi(
      '/api/system/systemPagePerformanceLog/deleteSystemPagePerformanceLog',
      'POST',
      this.state.params
    ).then(() => {
      this.setState({ clearLoading: false });
      this.search();
    }).catch(e => {
      this.setState({ clearLoading: false });
      message.error('接口错误');
    })
  }

  anlayze = () => {
    this.setState({ reportLoading: true });
    // setTimeout(() => {
    //   this.setState({ anlayzeData: mock.datas, showReport: true, reportLoading: false });
    // }, 1000);
    callApi(
      '/api/system/systemPagePerformanceLog/selectSystemPagePerformanceLog',
      'POST',
      this.state.params
    ).then(result => {
      callApi('/api/ec/dev/table/datas', 'POST', {
        ...this.state.params,
        dataKey: result.datas,
        current: 1,
        pageSize: 10000,
      }).then(res => {
        this.setState({ anlayzeData: res.datas, showReport: true, reportLoading: false });
      }).catch(e => {
        this.setState({ reportLoading: false });
        message.error('接口错误');
      });
    }).catch(e => {
      this.setState({ reportLoading: false });
      message.error('接口错误');
    })
  }

  search = () => {
    this.setState({ searchLoading: true });
    callApi(
      '/api/system/systemPagePerformanceLog/selectSystemPagePerformanceLog',
      'POST',
      this.state.params
    ).then(result => {
      const { tableStore } = this.props;
      tableStore.getDatas(result.datas, 1, undefined, this.state.sortParams);
      this.setState({ searchLoading: false });
    }).catch(e => {
      this.setState({ searchLoading: false });
      message.error('接口错误');
    })
  }

  getOpen = () => {
    this.setState({ openLoading: true });
    callApi(
      '/api/system/systemPagePerformanceLog/getSystemPagePerformanceConfigSwitch',
      'GET',
      { name: 'systemPerformanceSwaticRun' }
    ).then(({ isopen }) => {
      this.setState({ openLoading: false, isopen });
    }).catch(e => {
      this.setState({ openLoading: false });
      message.error('接口错误');
    })
  }

  open = (status) => {
    this.setState({ openLoading: true });
    return callApi(
      '/api/system/systemPagePerformanceLog/settingSystemPagePerformanceRun',
      'POST',
      { name: 'systemPerformanceSwaticRun', status }
    ).then(result => {
      if (result.status) {
        this.setState({ openLoading: false, isopen: status });
      }
    }).catch(e => {
      this.setState({ openLoading: false });
      message.error('接口错误');
    })
  }

  getFilter = (k, search) => {
    const filter = filterContants[k];
    if (!filter) return null;
    const { params } = this.state;
    let value = params[filter];
    if (filter === 'browser' && params.version) {
      value = `${params[filter]} ${params.version}`;
    }
    let overlay = (
      <WeaInput value={value} onChange={v => {
        const browserV = v.split(' ');
        const browserWithV = filter === 'browser' && browserV.length === 2 && browserV[1];
        this.setState({ params: {
          ...params,
          [filter]: browserWithV ? browserV[0] : v,
          ...(browserWithV ? { version: browserV[1] } : { version: '' }),
        }});
      }} />
    );
    const usrBrowser = k === 'PR_USERNAME' || k === 'PR_SUBCOMPANYNAME' || k === 'PR_DEPARTMENTNAME';
    const isStart = k === 'PR_START';
    const isRender = k === 'PR_RENDER';
    if (usrBrowser) {
      value = this.state[`${filter}Data`];
      const tabs = [
        { isSearch: true, key: '1', name: '按列表', selected: false, showOrder: 0, dataParams: { list: '1' } },
        { isSearch: false, key: '2', name: '组织结构', selected: false, showOrder: 0 },
      ];
      const browserSetting = {
        PR_USERNAME: { type: 17, title: '用户' },
        PR_SUBCOMPANYNAME : { type: 194, title: '分部', tabs  },
        PR_DEPARTMENTNAME: { type: 57, title: '部门', tabs },
      }
      overlay = (
        <WeaBrowser
          { ...browserSetting[k] }
          textDecoration={true}
          replaceDatas={value}
          isSingle={false}
          onChange={(ids, names, data)=> {
            this.setState({
              params: { ...params , [filter]: ids },
              [`${filter}Data`]: data
            }, () => !search && this.search())
          }}
        />
      )
    }
    if (isStart) {
      value = [
        params.startFrom ? transformDate(params.startFrom) : '',
        params.startTo ? transformDate(params.startTo) : '',
      ];
      overlay = (
        <RangePicker
          showTime
          value={value}
          format="yyyy-MM-dd HH:mm:ss"
          onChange={(value) => {
            const startFrom = value[0] || '';
            const startTo = value[1] || '';
            this.setState({ params: {
              ...params,
              startFrom: startFrom ?  new Date(startFrom).getTime() : '',
              startTo: startTo ?  new Date(startTo).getTime() : '',
            }}, () => !search && this.search())
          }}
        />
      )
    }
    if (isRender) {
      value = [params.renderFrom, params.renderTo];
      overlay = (
        <WeaScope
          isMobx
          min={[0,60000]}
          max={[0,60000]}
          value={value}
          onChange={v => this.setState({ params: {
            ...params,
            renderFrom: v[0] || '',
            renderTo: v[1] || '',
          }})}
        />
      );
    }
    const overlayClassName = classnames("wea-performance-filter", {
      'wea-performance-filter-nobtn': usrBrowser || k === 'PR_START',
    });
    if (search) {
      return (
        <div style={{ width: isStart || isRender ? 160 : 100, height: 60, float: 'left', marginRight: 10 }}>
          <p>{titleContants[k]}</p>
          {overlay}
        </div>
      )
    }
    let color = { color: '#2db7f5', fontWeight: 600 };
    if ((!value && value !==0) || (Array.isArray(value) && !value[0] && value !==0)) {
      if(Array.isArray(value) && value.length > 1 && (value[0] || value[1])){
        color = { color: '#2db7f5', fontWeight: 600 };
      } else {
        color = {};
      }
    }
    return (
      <Popconfirm overlayClassName={overlayClassName} placement="bottom" title={overlay} onConfirm={() => this.search()}>
        <i className="icon-coms-screen2" style={{ cursor: 'pointer', marginLeft: 5, ...color }} />
      </Popconfirm>
    );
  }

  getDetailCol = (data, dir) => {
    const desOrder = { ...detailContants };
    Object.keys(data).forEach(k => {
      const name = desOrder[k];
      const value = data[k];
      if (name && typeof value !== 'object' && value.toString() !== 'NaN') {
        desOrder[k] = value;
      }
    });
    const deleteKey = [];
    Object.keys(desOrder).forEach(k => {
      if (detailContants[k] === desOrder[k]) deleteKey.push(k);
    });
    deleteKey.forEach((k) => {
      delete desOrder[k];
    })
    const result = [];
    const contans = dir === 'left' ? orderContants.slice(0, 14) :
      dir === 'right' ? orderContants.slice(14, 28) : orderContants
    contans.forEach((k, i) => {
      if(typeof k !== 'string') {
        if(Object.keys(desOrder).filter(i => i === k.name).length) {
          result.push(
            <Collapse defaultActiveKey={['1']}>
              <Panel header={`${detailContants[k.name]} : ${data[k.name]}`} key={k}>
                {
                  k.detail.length && k.detail.map((i) => {
                    return (
                      <p key={detailContants[i]} style={{ wordBreak: 'break-all' }}>
                        {`- ${detailContants[i]} : `}
                        <span style={{ fontWeight: 600 }}>{data[i]}</span>
                      </p>
                    )
                  })
                }
              </Panel>
            </Collapse>
          );
        }
      } else {
        if(Object.keys(desOrder).filter(i => i === k).length) {
          const value = desOrder[k];
          result.push(
            <div key={detailContants[k]} style={{ wordBreak: 'vbreak-all' }} className="collapse-item">
              <Tooltip placement="bottomLeft" title={value}>
              <span>
                {`- ${detailContants[k]} : `}
                <span style={{ fontWeight: 600 }}>{value || 0}</span>
              </span>
              </Tooltip>
            </div>
          );
        }
      }
    });
    return (
      <div>{result}</div>
    );
  }

  transformKeys = (d) => {
    const result = {};
    Object.keys(d).forEach(k => {
      result[`PR_${k.toUpperCase()}`] = d[k];
    })
    return result;
  }

  getDetailResource = (data) => {
    let children = [];
    if (data.length) {
      data.forEach((d, i) => {
        const r = {};
        Object.keys(d).forEach(k => {
          const r_arr = ['name', 'start', 'TTFB', 'network', 'download', 'domainLookupStart', 'domainLookupEnd', 'connectStart', 'connectEnd', 'requestStart', 'responseStart', 'responseEnd', 'domainLookup', 'connect']
          if (r_arr.indexOf(k) > -1) {
            r[k] =  d[k];
          }
        })
        children.push(
            <Card style={{ margin: '1% 2%' }}>
              {this.getDetailCol(this.transformKeys(r))}
            </Card>
        );
      })
    }
    return children
  }

  getSorter = (orderkey, sortable, ascend) => {
    return (
      <span style={{ marginLeft: 5, fontWeight: 600, cursor: 'pointer' }} onClick={() => {
        const { sortParams } = this.state;
        let newParams = sortParams.map(s => ({ ...s }));
        if (sortable) {
          newParams = ascend ? sortParams.filter(s => s.orderkey !== orderkey)
            : sortParams.map(s => ({
              ...s,
              sortOrder: 'ascend'
            }));
        } else {
          newParams.push({ orderkey, sortOrder: 'descend' });
        }
        this.setState({ sortParams: newParams }, () => this.search());
      }}>
        { sortable
          ? <i className={`icon-coms-${ascend ? 'Reverse' : 'positive-sequence'}`} style={{ color: '#2db7f5', transform: 'scale(1.3)', display: 'inline-block' }} />
          : <i className="icon-coms02-coms-Row-operation" style={{ transform: 'rotate(90deg)', display: 'inline-block' }} />
        }
      </span>
    )
  }

  getColumns = () => {
    const columns = toJS(this.props.tableStore.columns);
    const keys = Object.keys(widthContants);
    const cols = [...keys];
    let x = 100;
    const style = { overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' };
    const iconStyle = { cursor: 'pointer', fontSize: 14, marginLeft: 15 };
    const { sortParams } = this.state;
    columns.forEach(col => {
      const { dataIndex } = col;
      const help = helpContants[dataIndex];
      let sortable = false;
      let ascend = false;
      // const orderkey = `t1.${dataIndex}`;
      sortParams.forEach(s => {
        if (s.orderkey === dataIndex) {
          sortable = true;
          if (s.sortOrder === 'ascend') {
            ascend = true;
          }
        }
      })
      const title = (
        <span>
          { titleContants[dataIndex] || col.title }
          { this.getFilter(dataIndex) }
          { dataIndex !== 'PR_CHILDREN' ? this.getSorter(dataIndex, sortable, ascend) : null }
          { help ? <WeaHelpfulTip style={{ marginLeft: 5 }} title={help} placement="topRight" /> : null }
        </span>
      )
      const newCol = {
        ...col,
        title,
        width: widthContants[dataIndex] || '10%',
        render: (text, record, index) => {
          const color = record.PR_RENDER > 5000 ? '#f5222d'
            : record.PR_RENDER > 2500 ? '#faad14'
            : dataIndex === 'PR_CHILDREN' ? '#2db7f5' : '#333';
          if (dataIndex === 'PR_START') {
            text = record.PR_STARTDATEspan;
          }
          if (dataIndex === 'PR_BROWSER') {
            text = `${text} ${record.PR_VERSION.replace(/\..*$/, '')}`;
          }
          if (dataIndex === 'PR_OS') {
            text = `${text} ${record.PR_OSVERSION.replace(/\..*$/, '')}`;
          }
          if (dataIndex === 'PR_CHILDREN') {
            const data = JSON.parse(record.PR_CHILDREN);
            return (
              <i className="icon-coms-rizhizhongxin" style={{ ...iconStyle, color  }}  onClick={() => this.getDetailDialog(record, data)} />
            )
          }
          if (dataIndex === 'PR_NAME') {
            return (
              <Tooltip placement="top" title={<div style={{ wordBreak: 'break-all' }}>{text}</div>}>
                <div style={{ ...style, color }} >{text}</div>
              </Tooltip>
            );
          }
          return (
            <div title={text} style={{ ...style, color }}>
              {text}
            </div>
          );
        }
      };
      const index = keys.findIndex((key) => key === dataIndex);
      if (index > -1) {
        cols[index] = newCol;
      }
    })
    return {
      columns: cols.filter(col => {
        x += col.width;
        return !!col.dataIndex;
      }),
      x,
    };
  }

  getPagination = () => {
    const { tableStore } = this.props;
    const { count, current, pageSize } = tableStore;
    const fn = (c, p) => tableStore.getDatas("", c, p || pageSize, {}, () => {}, false);
    return {
      current,
      total: count,
      showTotal: t => `共 ${t} 条`,
      pageSize,
      showSizeChanger: true,
      showQuickJumper: true,
      pageSizeOptions: [10, 20, 50, 100],
      onShowSizeChange: fn,
      onChange: fn,
    }
  }

  getReport = () => {
    const { anlayzeData, y } = this.state;
    const all = anlayzeData.length;
    if (!all) return <div style={{ marginTop: 100, fontSize: 30, textAlign: 'center' }}>暂无数据</div>;
    const json = {
      all,
      render: {
        '0s ~ 1s': 0,
        '1s ~ 2s': 0,
        '2s ~ 3s': 0,
        '3s ~ 4s': 0,
        '4s ~ 5s': 0,
        '5s +': 0,
      },
      page: {},
      browser: {},
      os: {},
      lastname: {},
    }
    const rangeFn = (key, value, data) => {
      if (value in json[key]) {
        json[key][value].num += 1;
        json[key][value].render += Number(data.PR_RENDER);
      } else {
        json[key][value] = {
          num: 1,
          render: Number(data.PR_RENDER),
          get average() {
            return parseInt(this.render / this.num);
          },
        };
      }
    }
    const data = anlayzeData.map(d => {
      const page = d.PR_NAME.replace(/\?.*$/, '').replace(/\#.*$/, '');
      rangeFn('page', page, d);
      const browser = `${d.PR_BROWSER} ${d.PR_VERSION.replace(/\..*$/, '')}`
      rangeFn('browser', browser, d);
      const lastname = d.PR_USERNAME;
      rangeFn('lastname', lastname, d);
      const os = `${d.PR_OS} ${d.PR_OSVERSION.replace(/\..*$/, '')}`
      rangeFn('os', os, d);
      const t = Number(d.PR_RENDER);
      (t <= 1000) && (json.render['0s ~ 1s'] += 1);
      (t <= 2000 && t > 1000) && (json.render['1s ~ 2s'] += 1);
      (t <= 3000 && t > 2000) && (json.render['2s ~ 3s'] += 1);
      (t <= 4000 && t > 3000) && (json.render['3s ~ 4s'] += 1);
      (t <= 5000 && t > 4000) && (json.render['4s ~ 5s'] += 1);
      (t > 5000) && (json.render['5s +'] += 1);
      return {
        ...d,
        page,
        children: JSON.parse(d.PR_CHILDREN),
      }
    });
    const rangeSeriesFn = (data, key) => {
      return data.map(name => ({
        name,
        value: json[key][name].average,
        num: json[key][name].num
      })).sort((a, b) => a.value > b.value ? 1 : -1);
    }
    const rangeMaxFn = (data) => {
      return data[data.length - 1] ? Math.ceil(data[data.length - 1].value / 1000) * 1000 : 3000;
    }
    const rangeKeys = ['page', 'browser', 'lastname', 'os'];
    const rangeYNames = ['URL', '浏览器', '用户', '操作系统'];
    const rangeArray = rangeKeys.map(id => {
      const keys = Object.keys(json[id]);
      const series = rangeSeriesFn(keys, id);
      const max = rangeMaxFn(series);
      return { id, keys, series, max };
    })
    const renderKeys = Object.keys(json.render);
    const renderSeries = renderKeys.map((name, i) => ({ name, value: json.render[name], visualMap: false }));
    const props = {
      useDefault: false,
      option: {
        color: WeaEchart.colors,
        tooltip : {},
        visualMap: {
          orient: 'horizontal',
          left: 'center',
          min: 0,
          max: 5000,
          dimension: 0,
          inRange: {
            color: ['#52c41a', '#1890ff', '#faad14', '#f5222d']
          }
        },
        title: [
          { text: '总耗时占比', subtext: `总计 ${json.all}`, x: '25%', textAlign: 'center'},
          { text: '总耗时分布', subtext: `总计 ${json.all}`, x: '75%', textAlign: 'center'},
          { text: '页面平均耗时排行', x: '25%', y: 380, textAlign: 'center', gridIndex: 1},
          { text: '浏览器平均耗时排行', x: '75%', y: 380, textAlign: 'center', gridIndex: 2},
          { text: '用户平均耗时排行', x: '25%', y: 780, textAlign: 'center', gridIndex: 3},
          { text: '操作系统平均耗时排行', x: '75%', y: 780, textAlign: 'center', gridIndex: 4},
        ],
        grid: [
          { top: 60, width: '40%', height: 300, left: '50%', containLabel: true },
          { top: 450, width: '40%', height: 300, left: 0, containLabel: true },
          { top: 450, width: '40%', height: 300, left: '50%', containLabel: true },
          { top: 850, width: '40%', height: 300, left: 0, containLabel: true },
          { top: 850, width: '40%', height: 300, left: '50%', containLabel: true },
        ],
        xAxis: [
          { type: 'category', name: '时间区间', data: renderKeys, axisLabel: { interval: 0, rotate: 30 } },
          ...rangeArray.map((r, i) => ({
            type: 'value', name: '平均耗时 (ms)', max: r.max, splitLine: { show: false }, gridIndex: i + 1,
          })),
        ],
        yAxis: [
          { type: 'value', name: '条数', max: json.all },
          ...rangeArray.map((r, i) => ({
            type: 'category', name: rangeYNames[i], data: r.keys, gridIndex: i + 1
          })),
        ],
        series: [
          {
            type: 'bar', barWidth: '60%', stack: 'render', z: 3,
            label: { normal: { position: 'top', show: true } },
            tooltip : { trigger: 'item', formatter: "{b} 条数 : {c}" },
            data: renderSeries, visualMap: false,
          },
          {
            type: 'pie',
            center: ['25%', 200],
            radius: [0, '18%'],
            tooltip : { trigger: 'item', formatter: "{b} 占比 : {c} ({d}%)" },
            data: renderSeries,
          },
          ...rangeArray.map((r, i) => ({
            type: 'bar', stack: r.id, xAxisIndex: i + 1, yAxisIndex: i + 1,
            label: { normal: { position: 'right', show: true } },
            tooltip : { trigger: 'item', formatter: (obj) => {
              return `${obj.data.name}<br>${obj.data.num} 条平均耗时 : ${obj.data.value} ms`;
            }},
            data: r.series,
          })),
        ],
      }
    };
    return (
      <div style={{ width: '100%', height: 1260, padding: '30px 50px' }}>
        <WeaEchart ref={el => (this.echart = el)} {...props} />
      </div>
    );
  }

  getTable = () => {
    const { tableStore } = this.props;
    const { loading, datas } = tableStore;
    const colSetting = this.getColumns();
    const { y, showReport, searchLoading } = this.state;
    return (
      <div ref={el => (this.table = el)} className="wea-new-table wea-performance-table">
        <div style={showReport ? { filter: 'blur(2px)' } : null}>
          <Table
            bordered={true}
            useFixedHeader={false}
            needWeaLoading={true}
            loadingWea={searchLoading || loading}
            columns={colSetting.columns}
            dataSource={toJS(datas)}
            pagination={false}
            scroll={{
              x: colSetting.x,
              y,
            }}
          />
          <Pagination
            className="ant-table-pagination"
            {...this.getPagination()}
          />
        </div>
        <div className="wea-performance-report" style={{ height: showReport ? y + 90 : 0 }}>
          {this.getReport()}
        </div>
      </div>
    );
  }

  getTags = (closable = true) => {
    const tags = [];
    const color = ['blue', 'green', 'yellow', 'red'];
    const { params } = this.state;
    const style = {
      maxWidth: 240,
      overflow: 'hidden',
      whiteSpace: 'nowrap',
      textOverflow: 'ellipsis',
      verticalAlign: 'middle',
      display: 'inline-block',
    };
    Object.keys(params).forEach((k, i) => {
      const value = params[k];
      const valueData = `${(this.state[`${k}Data`] || []).map(o => o.lastname || o.name)}`;
      if (value && k !== 'device' && k !== 'version') {
        let text = valueData || value;
        if (k === 'startTo') return;
        if (k === 'startFrom') {
          if (text === params.startTo) {
            text = transformDate(text).replace(/\s.*$/, '');
          } else {
            text = `${transformDate(text)} ~ ${transformDate(params.startTo)}`;
          }
        }
        if (k === 'renderFrom') {
          text = `大于 ${(text)} ms`;
        }
        if (k === 'renderTo') {
          text = `小于 ${(text)} ms`;
        }
        if (k === 'browser' && params.version) {
          text = `${(text)} ${params.version}`;
        }
        tags.push({
          onClose: () => {
            this.setState({
              params: {
                ...params,
                [k]: '',
                ...(k === 'startFrom' ? { startTo: '' } : {}),
                ...(k === 'browser' ? { version: '' } : {})
              },
              ...(valueData ? {[`${k}Data`]: [] } : {}),
            }, () => this.search());
          },
          text,
        });
      }
    });
    return tags.map((t, i) => (
      <Tag key={`${t.text}_${i}`} closable={closable} color={color[i % 4]} {...t} >
        <span style={style}>{t.text}</span>
      </Tag>
    ));
  }

  getSearchHeader = () => {
    const style = { marginRight: 5 };
    return (
      <div>
        <div style={{ float: 'left' }}>查询条件</div>
        <div style={{ position: 'relative', minHeight: 30, marginLeft: 55, padding: '0 160px 0 14px', overflow: 'hidden', cursor: 'auto' }} onClick={e => e.stopPropagation()} >
          {this.getTags()}
          <Button  style={{ position: 'absolute', right: 84, top: 3 }} type='primary' size="small" onClick={() => this.search()}>
            <i className="icon-coms-search" style={{ ...style, fontWeight: 600 }} />查询
          </Button>
          <Button type='primary' size="small" style={{ position: 'absolute', right: 14, top: 3 }} onClick={e => {
            this.setState({ params: { ...initParams, device: this.state.params.device }, sortParams: [], lastnameData: [], subcompanynameData: [], departmentnameData: [] }, () => this.search());
          }}><i className="icon-coms-Web-service" style={style} />重置</Button>
        </div>
      </div>
    );
  }

  getSearch = () => {
    return (
      <div>
        <Collapse
          defaultActiveKey={['']}
          onChange={() => {
            this.timer = setTimeout(() => {
              this.caulate();
              clearTimeout(this.timer);
              this.timer = null;
            }, 300)
          }}
        >
          <Panel key="1" header={this.getSearchHeader()}>
            <div style={{ margin: '0 auto', width: 1010, paddingTop: 10 }}>
              { Object.keys(filterContants).map(k => this.getFilter(k, true)) }
            </div>
          </Panel>
        </Collapse>
      </div>
    )
  }

  getTitle = () => {
    const { params } = this.state;
    const data = {
      PC: '性能查询 - PC 端',
      Mobile: '性能查询 - 移动端',
    };
    const menu = (
      <Menu onClick={({ key }) => this.setState({ params: { ...initParams, device: key }, sortParams: [], lastnameData: [], subcompanynameData: [], departmentnameData: [] }, () => this.search())}>
        <Menu.Item key="PC">{data.PC}</Menu.Item>
        <Menu.Item key="Mobile">{data.Mobile}</Menu.Item>
      </Menu>
    );
    return (
      <Dropdown overlay={menu}>
        <span style={{ cursor: 'pointer', color: '#fff' }}>
          {data[params.device]}
          <i className="icon-coms-down2" style={{ marginLeft: 10 }} />
        </span>
      </Dropdown>
    );
  }

  getBtns = () => {
    const { tableStore } = this.props;
    const style = { marginRight: 5, fontWeight: 600 };
    const { params, reportLoading, clearLoading, showReport, openLoading, isopen } = this.state;
    const help = '根据查询条件获取最多 10000 条数据进行统计分析';
    return [
      <Button loading={reportLoading} type="primary" onClick={() => this.anlayze()}>
        {reportLoading ? '' : <i className="icon-coms-reportform" style={style} />}
        {reportLoading ? '统计分析中...' :'生成统计分析'}
        <WeaHelpfulTip style={{ marginLeft: 5 }} title={help} placement="bottomRight" />
      </Button>,
      <Button type="primary" onClick={() => this.setState({ showReport: !showReport })}>
        <i className={`icon-coms-${showReport ? 'hide' :'display'}`} style={style} />
        {`${showReport ? '关闭' : '显示'}统计分析`}
      </Button>,
      <Button type="primary" onClick={() => tableStore.exportAll()}>
        <i className="icon-coms-download" style={style} />导出EXCEL
      </Button>,
      <Popconfirm placement="bottom" title="确定要清空所有数据吗？" onConfirm={() => this.clear()}>
        <Button type="primary">
          <i className="icon-coms-delete" style={style}/>
          {clearLoading ? '清理中...' :'清空日志'}
        </Button>
      </Popconfirm>,
      <Switch disabled={openLoading} checked={isopen} checkedChildren="开" unCheckedChildren="关" onChange={this.open} />,
      <a style={{ color: '#fff' }} href="https://e-cloudstore.com/doc.html?appId=e5dd36e704634589be2710915c58127d" target="_blank">
        <i className="icon-coms-doc" style={style}/>
        使用说明
      </a>
    ];
  }

  getDetailDialog = (record, data) => {
    this.setState({
      visible: true,
      detailObj: { record, data }
    })
  }

  render() {
    const { tableStore } = this.props;
    const { loading } = tableStore;
    const { searchLoading, reportLoading, clearLoading, visible, detailObj } = this.state;
    return (
      <WeaTop
        className="wea-performance-top"
        loading={loading || searchLoading || reportLoading || clearLoading}
        icon={<i className="icon-coms-Pie" />}
        iconBgcolor="#57c5f7"
        title={this.getTitle()}
        buttons={this.getBtns()}
        heightSpace={0}
      >
        <div className="wea-performance-wrap" style={{ height: '100%', overflow: 'hidden' }}>
          {this.getSearch()}
          {this.getTable()}
        </div>
          <WeaDialog
            onCancel={() => this.setState({ visible: false })}
            title={`${detailObj.record.PR_USERNAME} - ${detailObj.record.PR_NAME}`}
            icon='icon-coms-rizhizhongxin'
            maskClosable={true}
            visible={visible}
            style={{ width: '70%', height: 800 }}
            hasScroll
            scalable
            className="wea-performance-detail-dialog"
          >
            <Card style={{ margin: '1% 2%' }}>
              <Row type="flex" justify="space-around">
                <Col span={11}>
                  {this.getDetailCol(detailObj.record, 'left')}
                </Col>
                <Col span={11}>
                  {this.getDetailCol(detailObj.record, 'right')}
                </Col>
              </Row>
            </Card>
            {this.getDetailResource(detailObj.data)}
          </WeaDialog>
      </WeaTop>
    );
  }
}

const Root = () => (
  <Router history={history}>
    <Route name='/' path='/' component={(props) => <Main {...props} tableStore={tableStore} />} />
    <Route name='pc' path='/pc' component={(props) => <PC {...props} tableStore={pcTableStore} />} />
    <Route name='m' path='/m' component={M} />
  </Router>
);

ReactDOM.render(<Root />, document.getElementById('container'));

// https://e-cloudstore.com/ecode/doc?appId=e5dd36e704634589be2710915c58127d